package helper.base.math

import helper.base.list.DoubleListList

object DoubleMatrixHelper {
    open class DoubleMatrix(
        val rows: Int,
        val cols: Int,
        var matrix: ArrayList<ArrayList<Double>>,
    ) {
        companion object {
            fun makeDoubleMatrix(
                rows: Int,
                cols: Int,
            ): DoubleMatrix {
                return DoubleMatrix(
                    rows,
                    cols,
                    ArrayList<ArrayList<Double>>(
                        rows,
                    ).also {
                        for (i in 0 until rows) {
                            val row = ArrayList<Double>(cols)
                            for (j in 0 until cols) {
                                row.add(0.0)
                            }
                            it.add(row)
                        }
                    },
                )
            }

            fun makeDoubleMatrix(
                matrixSize: Int
            ): DoubleMatrix {
                return makeDoubleMatrix(
                    matrixSize,
                    matrixSize,
                )
            }

            fun makeDoubleMatrix(
                matrix: ArrayList<ArrayList<Double>>,
            ): DoubleMatrix {
                val rows = matrix.size
                val cols = matrix[0].size // 假设所有行具有相同的列数
                return DoubleMatrix(
                    rows,
                    cols,
                    matrix,
                )
            }
        }

        object Expand {
            fun DoubleListList.toDoubleMatrix(
            ): DoubleMatrix {
                return makeDoubleMatrix(this)
            }
        }

        operator fun set(
            row: Int,
            col: Int,
            value: Number,
        ) {
            matrix[row][col] = value.toDouble()
        }

        operator fun get(
            row: Int,
            col: Int,
        ): Double {
            return matrix[row][col]
        }

        fun setMany(
            ds: List<Double>,
        ) {
            var index = 0
            for (i in 0 until rows) {
                for (j in 0 until cols) {
                    this[i, j] = ds[index++]
                    if (index == ds.size) return
                }
            }
        }

        operator fun plus(
            other: DoubleMatrix
        ): DoubleMatrix {
            require(rows == other.rows && cols == other.cols)
            val result = makeDoubleMatrix(rows, cols)
            for (i in 0 until rows) {
                for (j in 0 until cols) {
                    result[i, j] = this[i, j] + other[i, j]
                }
            }
            return result
        }

        private fun samePositionValueCompare(
            other: DoubleMatrix,
            compareFun: (Double, Double) -> Boolean,
        ): Boolean {
            if (this === other) return true
            if (rows != other.rows || cols != other.cols) return false

            for (i in 0 until rows) {
                for (j in 0 until cols) {
                    if (compareFun(matrix[i][j], other[i, j])) continue
                    return false
                }
            }
            return true
        }

        fun isSamePositionValueEquals(other: DoubleMatrix): Boolean {
            return samePositionValueCompare(other) { v1, v2 ->
                v1 == v2
            }
        }

        fun isSamePositionValueLess(other: DoubleMatrix): Boolean {
            return samePositionValueCompare(other) { v1, v2 ->
                v1 < v2
            }
        }

        fun isSamePositionValueLessEquals(other: DoubleMatrix): Boolean {
            return samePositionValueCompare(other) { v1, v2 ->
                v1 <= v2
            }
        }

        fun print() {
            for (row in matrix) {
                for (element in row) {
                    print("$element ")
                }
                println()
            }
        }
    }
}